#ifndef __GLOBALS_H__
#define __GLOBALS_H__

#include "unp.h"
#include "hw_addrs.h"

#include <netpacket/packet.h>
#include <net/ethernet.h> 
#include <net/if_arp.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/if_ether.h>
#include <setjmp.h>

# define RREQ_MSG_LEN (1500 - 2*INET_ADDRSTRLEN - 5*sizeof(int) - ETH_ALEN)
# define RREP_MSG_LEN (1500 - 2*INET_ADDRSTRLEN - 3*sizeof(int))
# define APP_MSG_LEN (1500 - 2*INET_ADDRSTRLEN - 5*sizeof(int))

#define NUM_INTERFACES 2
#define PROTO_NUM 9713
#define ETH_FRAME_LEN 1514
#define RAND_MAX 100
#define HW_ADDR_LEN 6
#define SERV_PORT 4094
#define CLIENT_TIMEOUT 2

#define CLI_DG_PATH "group5_cli.dg"
#define SRV_DG_PATH "group5_srv.dg"
#define SRV_WELL_KNOWN_PATH "group5_srv_4094.dg"

#define check_err(err, msg) \
if (err < 0)\
{\
	perror(msg);\
	exit(1);\
}

#define trace printf("%s: %d\n", __FILE__, __LINE__)

typedef struct
{
	int cli_port;
	char sunpath[104];
	struct timeval  timestamp;
	int per_flag;
}client_info;

struct client_info_table 
{
	client_info * entry;
	struct client_info_table * next;
};

typedef struct client_info_table cli_log;

typedef struct 
{
	int type;
	//char source_id[INET_ADDRSTRLEN];
	//char dest_id[INET_ADDRSTRLEN];
        struct in_addr source_id;
	struct in_addr dest_id;
	char source_mac[ETH_ALEN];
	int broadcast_id;
	int hop_count;
	int forced_disc;
	int rrep_sent;
	char data[RREQ_MSG_LEN];
}RREQ_hdr;

typedef struct 
{
	int type;
	//char source_id[INET_ADDRSTRLEN];
	//char dest_id[INET_ADDRSTRLEN];
        struct in_addr source_id;
	struct in_addr dest_id;
	int broadcast_id;
	int hop_count;
	char data[RREP_MSG_LEN];
}RREP_hdr;

typedef struct
{
	int sockfd;
    int ifindex;
    char mac_addr[HW_ADDR_LEN];
	struct sockaddr_ll socket_address;
}sock_desc;

typedef struct 
{
	int type;
	//char source_id[INET_ADDRSTRLEN];
	int source_port;
	//char dest_id[INET_ADDRSTRLEN];
        struct in_addr source_id;
	struct in_addr dest_id;
	int dest_port;
	int hop_count;
	int data_len;
	char data[APP_MSG_LEN];
}APP_hdr;

typedef struct
{
        char dest[INET_ADDRSTRLEN]; 
        unsigned char next_hop[HW_ADDR_LEN];
        int ifindex;
        int hop_count;
        struct timeval timestamp;
}node;

typedef struct
{
    char source_id[INET_ADDRSTRLEN];
    int broadcast_id;
}broadcast_recv;

struct broadcast_l
{
    broadcast_recv * bl_recv;
    struct broadcast_l * bl_link;
};

typedef struct broadcast_l broadcast_list;

struct routing_table
{
        node * entry;
        struct routing_table * next;
};


typedef struct routing_table table;

//
// Forwared declarations of functions.
//

void 
msg_send(
	int sockfd, 
	char addr[INET_ADDRSTRLEN], 
	int portno, 
	char msg[], 
	int flag
	);

void
flood_interface(
        sock_desc sock,
        void * data_to_send,
        size_t len_data
        );

void 
flood_all_interfaces(
        sock_desc sockets[],
        int num_socks,
        void * data_to_send,
        size_t len_data
        );

void
send_unicast(
        int sockfd,
        char src_mac[],
        char dest_mac[],
        int ifindex,
        void * data_to_send,
        size_t len_data
        );

char *  
parse_msg_send_data( 
        char msg[1000],
        int * clisockfd,
        char ip_addr[INET_ADDRSTRLEN],
        int * portno,
        int * flag,
        char * sun_path
        );

RREQ_hdr *
generate_rreq(
        char src_id[],
        char dst_id[],
	int * broadcast_id,
        int disc_flag
        );
char*
get_odr_ip();

RREP_hdr *
generate_rrep(
        char src_id[],
        char dst_id[],
        int * broadcast_id	
	);	

APP_hdr*
create_app_data(
        char source_id[],
        int source_port,
        char dest_id[],
        int dest_port,
        int hop_count,
        int data_len,
        char data[]
        );

char *
create_stream_msg_recv(
        APP_hdr* app_data
        );

char *  
parse_msg_receive_data( 
        char msg[1000],
        char ip_addr[INET_ADDRSTRLEN],
        int * portno
        );

char *
get_vmname_from_ip(
        char ip[]
        );

void add_client(cli_log * cli_info, char * sun_path, int flag, int tmp_port);

char * find_client_sunpath(cli_log * cli_info, int port);

int find_client(cli_log * cli_info, char * sun_path);

void delete_client(cli_log * cli_info, int port);

int isstale (struct timeval ts, int staleness, char * dest);

#endif
